"""
清理相关的Celery任务
"""

import asyncio
from datetime import datetime, timedelta
from typing import Dict, Any, List
from sqlalchemy.orm import Session

from app.celery_app import celery_app, task_with_retry
from app.database import SessionLocal, get_async_db
from app.models import Monitor, ProductNotification, Notification, User
from app.models.monitor import MonitorStatus
from app.services.monitor_service import MonitorService
# 延迟导入 wechat_service，避免 Celery Beat 启动时初始化微信服务
# from app.services.wechat_service import wechat_service
from app.utils.redis_client import get_redis_client
from app.utils.logger import get_monitor_logger

# 获取日志记录器
cleanup_logger = get_monitor_logger()


@task_with_retry(queue="cleanup")
def check_expired_monitors_task(self) -> Dict[str, Any]:
    """
    定期检查并更新过期监控状态
    每5分钟执行一次，调用 monitor_service 的 check_expired_monitors 方法
    """
    try:
        cleanup_logger.info("🔍 开始检查过期监控任务")
        start_time = datetime.now()

        # 使用同步数据库会话，避免异步事件循环问题
        from app.database import SessionLocal
        from app.models.monitor import Monitor, MonitorStatus

        # 北京时间函数（本地定义，避免循环导入）
        def get_beijing_now():
            """获取北京时间（UTC+8）"""
            from datetime import datetime, timedelta
            return datetime.utcnow() + timedelta(hours=8)

        db = SessionLocal()
        expired_monitors_data = []  # 存储过期监控的数据，而不是ORM对象

        try:
            # 直接使用同步查询，避免异步复杂性
            current_time = get_beijing_now()

            # 查询过期的监控任务
            expired_monitors = db.query(Monitor).filter(
                Monitor.is_active == True,
                Monitor.expires_at < current_time
            ).all()

            # 更新过期监控的状态并收集数据
            for monitor in expired_monitors:
                # 在会话内收集需要的数据（包括用户信息）
                user = db.query(User).filter(User.id == monitor.user_id).first()
                monitor_data = {
                    "id": monitor.id,
                    "name": monitor.name,
                    "user_id": monitor.user_id,
                    "monitor_type": monitor.monitor_type.value if hasattr(monitor, 'monitor_type') else 'keyword',
                    "expires_at": monitor.expires_at.isoformat() if monitor.expires_at else None,
                    "user_openid": getattr(user, 'openid', None) if user else None,
                    "user_channel": (getattr(user, 'channel', 'EMAIL') or 'EMAIL').upper() if user else 'EMAIL'
                    
                }
                expired_monitors_data.append(monitor_data)

                # 更新状态
                monitor.is_active = False
                monitor.status = MonitorStatus.EXPIRED
                monitor.updated_at = current_time
                cleanup_logger.info(f"📋 监控 {monitor.id} ({monitor.name}) 已过期")

            # 提交更改
            if expired_monitors:
                db.commit()
                cleanup_logger.info(f"✅ 成功更新 {len(expired_monitors)} 个过期监控")
                
                # 为微信用户发送过期通知
                for monitor_data in expired_monitors_data:
                    if (monitor_data.get('user_channel') == 'WECHAT' and 
                        monitor_data.get('user_openid')):
                        
                        cleanup_logger.info(f"📱 准备为用户 {monitor_data['user_id']} 发送监控过期通知")
                        
                        try:
                            # 使用线程运行异步通知，避免阻塞主流程
                            import threading
                            import asyncio
                            
                            def send_expiry_notification():
                                """In thread中发送过期通知"""
                                loop = None
                                try:
                                    loop = asyncio.new_event_loop()
                                    asyncio.set_event_loop(loop)
                                    
                                    # 延迟导入，避免 Celery Beat 启动时初始化微信服务
                                    from app.services.wechat_service import wechat_service as _wechat_service
                                    success = loop.run_until_complete(
                                        _wechat_service.send_expiry_notification(
                                            openid=monitor_data['user_openid'],
                                            monitor_name=monitor_data['name'],
                                            expires_at=monitor_data['expires_at'],
                                            monitor_type=monitor_data['monitor_type']
                                        )
                                    )
                                    
                                    if success:
                                        cleanup_logger.info(f"✅ 监控 {monitor_data['id']} 过期通知发送成功")
                                    else:
                                        cleanup_logger.warning(f"⚠️ 监控 {monitor_data['id']} 过期通知发送失败")
                                        
                                except Exception as notify_error:
                                    cleanup_logger.error(f"❌ 监控 {monitor_data['id']} 过期通知异常: {notify_error}")
                                finally:
                                    if loop and not loop.is_closed():
                                        try:
                                            pending = asyncio.all_tasks(loop)
                                            if pending:
                                                loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True))
                                            loop.close()
                                        except Exception:
                                            pass
                            
                            # 在线程中发送通知，不阻塞主流程
                            notification_thread = threading.Thread(target=send_expiry_notification)
                            notification_thread.start()
                            notification_thread.join(timeout=10)  # 最多等待10秒
                            
                            if notification_thread.is_alive():
                                cleanup_logger.warning(f"⚠️ 监控 {monitor_data['id']} 过期通知发送超时")
                            
                        except Exception as thread_error:
                            cleanup_logger.error(f"❌ 监控 {monitor_data['id']} 过期通知线程异常: {thread_error}")
                    
                    elif monitor_data.get('user_channel') == 'WECHAT':
                        cleanup_logger.info(f"📱 用户 {monitor_data['user_id']} 为微信用户但缺少OpenID，跳过通知")
                    else:
                        cleanup_logger.debug(f"📫 用户 {monitor_data['user_id']} 不是微信用户（{monitor_data.get('user_channel')}），跳过通知")
                        
            else:
                cleanup_logger.debug("📊 未发现过期监控")

        except Exception as db_error:
            db.rollback()
            cleanup_logger.error(f"❌ 数据库操作失败: {db_error}")
            raise
        finally:
            db.close()

        # 记录结果
        end_time = datetime.now()
        duration = (end_time - start_time).total_seconds()

        cleanup_logger.info(f"✅ 过期监控检查完成:")
        cleanup_logger.info(f"   - 检查耗时: {duration:.2f}秒")
        cleanup_logger.info(f"   - 过期监控数: {len(expired_monitors_data)}")

        # 记录过期监控详情
        for monitor_data in expired_monitors_data:
            cleanup_logger.info(f"   - 监控 {monitor_data['id']} ({monitor_data['name']}) 已标记为过期")

        return {
            "status": "success",
            "expired_count": len(expired_monitors_data),
            "expired_monitors": expired_monitors_data,
            "duration_seconds": duration,
            "timestamp": datetime.now().isoformat(),
            "message": f"成功检查过期监控，发现 {len(expired_monitors_data)} 个过期任务"
        }

    except Exception as exc:
        error_msg = str(exc)
        cleanup_logger.error(f"❌ 过期监控检查失败: {error_msg}")

        return {
            "status": "error",
            "error": error_msg,
            "timestamp": datetime.now().isoformat(),
            "message": "过期监控检查失败"
        }


@task_with_retry(queue="cleanup")
def cleanup_expired_cache(self) -> Dict[str, Any]:
    """
    清理过期的Redis缓存数据
    """
    try:
        redis_client = get_redis_client()
        
        # 获取所有商品缓存键
        pattern = "product_seen:*"
        keys = redis_client.keys(pattern)
        
        expired_count = 0
        for key in keys:
            # 检查TTL，如果已过期则删除
            ttl = redis_client.ttl(key)
            if ttl == -1:  # 没有设置过期时间的键
                redis_client.expire(key, 86400)  # 设置24小时过期
            elif ttl == -2:  # 已过期的键
                redis_client.delete(key)
                expired_count += 1
        
        return {
            "status": "success",
            "total_keys": len(keys),
            "expired_cleaned": expired_count,
            "message": "缓存清理完成"
        }
        
    except Exception as exc:
        print(f"❌ 缓存清理失败: {exc}")
        raise self.retry(countdown=300, exc=exc)


@task_with_retry(queue="cleanup")
def cleanup_old_notifications(self) -> Dict[str, Any]:
    """
    清理30天前的通知记录
    """
    try:
        db = SessionLocal()
        
        # 计算30天前的时间
        cutoff_date = datetime.utcnow() - timedelta(days=30)
        
        # 删除旧的商品通知记录
        product_notifications_deleted = db.query(ProductNotification).filter(
            ProductNotification.created_at < cutoff_date
        ).delete()
        
        # 删除旧的通知记录
        notifications_deleted = db.query(Notification).filter(
            Notification.created_at < cutoff_date
        ).delete()
        
        db.commit()
        db.close()
        
        return {
            "status": "success",
            "product_notifications_deleted": product_notifications_deleted,
            "notifications_deleted": notifications_deleted,
            "cutoff_date": cutoff_date.isoformat(),
            "message": "旧通知记录清理完成"
        }
        
    except Exception as exc:
        print(f"❌ 通知记录清理失败: {exc}")
        raise self.retry(countdown=300, exc=exc)


@task_with_retry(queue="cleanup")
def cleanup_inactive_monitors(self) -> Dict[str, Any]:
    """
    清理非活跃的监控任务
    """
    try:
        db = SessionLocal()
        
        # 获取过期的监控任务
        expired_monitors = db.query(Monitor).filter(
            Monitor.expires_at < datetime.utcnow(),
            Monitor.status == MonitorStatus.ACTIVE
        ).all()
        
        # 将过期监控设为已过期状态
        expired_count = 0
        for monitor in expired_monitors:
            monitor.status = MonitorStatus.EXPIRED
            expired_count += 1
        
        # 删除7天前停止的监控任务
        cutoff_date = datetime.utcnow() - timedelta(days=7)
        deleted_count = db.query(Monitor).filter(
            Monitor.status == MonitorStatus.STOPPED,
            Monitor.stopped_at < cutoff_date
        ).delete()
        
        db.commit()
        db.close()
        
        return {
            "status": "success",
            "expired_monitors": expired_count,
            "deleted_monitors": deleted_count,
            "message": "非活跃监控清理完成"
        }
        
    except Exception as exc:
        print(f"❌ 监控清理失败: {exc}")
        raise self.retry(countdown=300, exc=exc)


@task_with_retry(queue="cleanup")
def cleanup_user_cache(self, user_id: int) -> Dict[str, Any]:
    """
    清理特定用户的缓存数据
    
    Args:
        user_id: 用户ID
    """
    try:
        redis_client = get_redis_client()
        
        # 清理用户相关的缓存
        patterns = [
            f"user:{user_id}:*",
            f"monitor:user:{user_id}:*",
            f"balance:{user_id}:*"
        ]
        
        total_deleted = 0
        for pattern in patterns:
            keys = redis_client.keys(pattern)
            if keys:
                deleted = redis_client.delete(*keys)
                total_deleted += deleted
        
        return {
            "status": "success",
            "user_id": user_id,
            "keys_deleted": total_deleted,
            "message": "用户缓存清理完成"
        }
        
    except Exception as exc:
        print(f"❌ 用户缓存清理失败: {exc}")
        raise self.retry(countdown=60, exc=exc)
